#include "Links.h"
#include "Handlers.h"
#include "Link.h"
#include "XMLTree.h"
#include "HBSD.h"
#include "ConfigFile.h"

using namespace std;

Links::Links(Handlers* router) 
{
	this->router = router;
	int hashCapacity = HBSD::routerConf->getInt(string("linksHashCapacity"), DEFAULT_HASH_CAPACITY);
	sem_init(&linksLock, 0, 1);
}

Links::~Links()
{
	sem_destroy(&linksLock);
	while(!linkMap.empty())
	{
		map<string,Link*>::iterator iter = linkMap.begin();
		delete iter->second;
		linkMap.erase(iter);
	}
}


Link* Links::create(XMLTree* evt) 
{
	// Get the link id.
	if (!evt->haveAttr(string("link_id"))) 
	{
		return NULL;
	}

	string id = evt->getAttr(string("link_id"));
	// Do we already know about the id? The key may exist from
	// a previous incarnation, but the object should be NULL.
	Link* link = getById(id);
	if (link != NULL) 
	{
		if (HBSD::log->enabled(Logging::WARN)) 
		{
			HBSD::log->warn(string("Ignoringing request to create an existing link: ") + id);
		}
		return NULL;
	}
	
	// Create the new link.
	link = new Link(this);
	if (!link->init(evt)) 
	{
		return NULL;
	}
	add(link);
	router->policyMgr->linkCreated(link);
	return link;
}

void Links::deleteEvt(XMLTree* evt) 
{
	// Remove the link in a synchronized method.
	Link* link = remove(evt);
	// Call into the link to delete itself without holding the
	// semaphore.
	link->deleted(evt);
}

int Links::numLinks() 
{
	sem_wait(&linksLock);
	int sz = linkMap.size();
	sem_post(&linksLock);
	return sz;
}

Link* Links::getById(string id) 
{
	Link* link = NULL;
	sem_wait(&linksLock);
	link = linkMap[id];
	sem_post(&linksLock);
	return link;
}

void Links::add(Link* link) 
{
	
	map<string,Link*>::iterator iter;

	sem_wait(&linksLock);

	iter = linkMap.find(link->id);
	if (iter != linkMap.end()) 
	{
		delete iter->second;
		linkMap.erase(iter);
	}

	linkMap[link->id] = link;

	sem_post(&linksLock);
}

Link* Links::remove(XMLTree* evt) 	
{
	// Get the link id.
	if (!evt->haveAttr(string("link_id"))) 
	{
		return NULL;
	}
	string id = evt->getAttr(string("link_id"));
	// Do we know about it?
	Link* link = NULL;
	sem_wait(&linksLock);
	link = linkMap[id];
	if (link == NULL) 
	{
		sem_post(&linksLock);
		if (HBSD::log->enabled(Logging::WARN)) 
		{
			HBSD::log->warn(string("Ignoringing request to delete a non-existent link: ") + id);
		}
		return NULL;
	}
	// Now remove it from the hash table.
	linkMap.erase(id);
	sem_post(&linksLock);
	router->policyMgr->linkDeleted(link);
	return link;
}

